package top.albertiy;

import jdk.nashorn.internal.runtime.StoredScript;
import top.albertiy.中介者模式.Mediator;
import top.albertiy.中介者模式.MyMediator;
import top.albertiy.单例模式.Singleton;
import top.albertiy.命令模式.Command;
import top.albertiy.命令模式.Invoker;
import top.albertiy.命令模式.MyCommand;
import top.albertiy.命令模式.Receiver;
import top.albertiy.备忘录模式.Original;
import top.albertiy.备忘录模式.Storage;
import top.albertiy.外观模式.Computer;
import top.albertiy.工厂方法模式.普通工厂模式.SendFactory;
import top.albertiy.工厂方法模式.普通工厂模式.Sender;
import top.albertiy.建造者模式.Builder;
import top.albertiy.抽象工厂模式.Provider;
import top.albertiy.抽象工厂模式.SendMailFactory;
import top.albertiy.桥接模式.Bridge;
import top.albertiy.桥接模式.MyBridge;
import top.albertiy.状态模式.Context;
import top.albertiy.状态模式.State;
import top.albertiy.策略模式.AbstractCalculator;
import top.albertiy.策略模式.ICalculator;
import top.albertiy.策略模式.Plus;
import top.albertiy.组合模式.Tree;
import top.albertiy.组合模式.TreeNode;
import top.albertiy.装饰模式.Decorator;
import top.albertiy.观察者模式.MySubject;
import top.albertiy.观察者模式.Observer1;
import top.albertiy.观察者模式.Observer2;
import top.albertiy.观察者模式.Subject;
import top.albertiy.访问者模式.MyVisitor;
import top.albertiy.访问者模式.Visitor;
import top.albertiy.责任链模式.MyHandler;
import top.albertiy.迭代子模式.Collection;
import top.albertiy.迭代子模式.Iterator;
import top.albertiy.迭代子模式.MyCollection;
import top.albertiy.迭代子模式.MyIterator;
import top.albertiy.适配器模式.Source;
import top.albertiy.适配器模式.对象的适配器模式.Wrapper;
import top.albertiy.适配器模式.接口的适配器模式.SourceSub1;
import top.albertiy.适配器模式.接口的适配器模式.SourceSub2;
import top.albertiy.适配器模式.接口的适配器模式.Sourceable;
import top.albertiy.适配器模式.类的适配器模式.Adapter;
import top.albertiy.适配器模式.Targetable;

public class Main {

    /**
     * 建立一个工厂类，增加一个工厂方法，对实现了同一接口的一些类进行实例的创建
     */
    public static void 普通工厂模式() {
        SendFactory factory = new SendFactory();
        Sender sender = factory.produce("sms");
        sender.send();
    }

    /**
     * 提供多个工厂方法
     */
    public static void 多个工厂方法模式() {
        top.albertiy.工厂方法模式.多个工厂方法模式.SendFactory factory = new top.albertiy.工厂方法模式.多个工厂方法模式.SendFactory();
        Sender sender = factory.produceMail();
        sender.send();
    }

    /**
     * 方法是静态的
     */
    public static void 静态工厂方法模式() {
        Sender sender = top.albertiy.工厂方法模式.静态工厂方法模式.SendFactory.produceMail();
        sender.send();
    }

    /**
     * 如果需要增加一个功能，只需做一个实现类实现Sender接口，同时做一个工厂类实现Provider接口，无需改动现成的代码，拓展性好
     */
    public static void 抽象工厂模式() {
        Provider provider = new SendMailFactory();
        Sender sender = provider.produce();
        sender.send();
    }

    public static void 单例模式() {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println("单例对象 s1 == s2? " + (singleton1 == singleton2));
    }

    /**
     * 工厂模式关注创建单个产品，建造者模式关注复合的对象，多个部分。
     */
    public static void 建造者模式() {
        Builder builder = new Builder();
        builder.produceMailSender(10);
    }

    /** 原型模式省略了，就是让一个类的对象可以复制自己 */

    /**
     * 适配器模式，通过一个适配器将目标接口和实现了目标接口中部分方法的类结合起来
     */
    public static void 类的适配器模式() {
        Targetable target = new Adapter();
        target.method1();
        target.method2();
    }

    /**
     * 对象的适配器模式，不继承 Source类，而是持有Source类的实例，以解决兼容性问题
     */
    public static void 对象的适配器模式() {
        Source source = new Source();
        Targetable target = new Wrapper(source);
        target.method1();
        target.method2();
    }

    /**
     * 当不希望实现一个接口中所有的方法时，可以创建一个抽象类Wrapper，实现所有方法，我们写别的类的时候，继承抽象类即可。
     */
    public static void 接口的适配器模式() {
        Sourceable source1 = new SourceSub1();
        Sourceable source2 = new SourceSub2();

        source1.method1();
        source1.method2();
        source2.method1();
        source2.method2();
    }

    /**
     * 装饰模式给一个对象增加一些新的功能，而且是动态的，要求装饰对象和被装饰对象实现同一个接口，装饰对象持有被装饰对象的实例
     */
    public static void 装饰模式() {
        top.albertiy.装饰模式.Sourceable source = new top.albertiy.装饰模式.Source();
        top.albertiy.装饰模式.Sourceable obj = new Decorator(source);
        obj.method();
    }

    /**
     * 采用一个代理类调用原有的方法，且对产生的结果进行控制。为的是对原有的方法进行改进，又不违反开闭原则。
     * 和装饰模式的区别是代理的对象不是动态的。
     */
    public static void 代理模式() {
        top.albertiy.代理模式.Sourceable source = new top.albertiy.代理模式.Proxy();
        source.method();
    }

    /**
     * 外观模式 Facade 很好理解，就是将类的继承关系转换成在一个新的类中的组合关系，起到解耦的作用。
     */
    public static void 外观模式() {
        Computer computer = new Computer();
        computer.startup();
        computer.shutdown();
    }

    /**
     * 桥接模式：将抽象化与实现化解耦，使二者可以独立变化，类似 JDBC的 DriverManager
     */
    public static void 桥接模式() {
        Bridge bridge = new MyBridge();
        /*调用第一个对象*/
        top.albertiy.桥接模式.Sourceable source1 = new top.albertiy.桥接模式.SourceSub1();
        bridge.setSource(source1);
        bridge.method();
        /*调用第二个对象*/
        top.albertiy.桥接模式.Sourceable sourec2 = new top.albertiy.桥接模式.SourceSub2();
        bridge.setSource(sourec2);
        bridge.method();
    }

    /**
     * 又名 部分-整体模式。适合处理树形结构问题。
     */
    public static void 组合模式() {
        Tree tree = new Tree("A");
        TreeNode nodeB = new TreeNode("B");
        TreeNode nodeC = new TreeNode("C");

        nodeB.add(nodeC);
        tree.root.add(nodeB);
        System.out.println("build the tree finished!");
    }

    public static void 策略模式() {
        String exp = "2+8";
        ICalculator cal = new Plus();
        int result = cal.calculate(exp);
        System.out.println(result);
    }

    public static void 模板方法模式() {
        String exp = "8+8";
        top.albertiy.模板方法模式.AbstractCalculator cal = new top.albertiy.模板方法模式.Plus();
        int result = cal.calculate(exp, "\\+");
        System.out.println(result);
    }

    /**
     * 观察者模式下，Subject 影响了 Observer
     */
    public static void 观察者模式() {
        Subject sub = new MySubject();
        sub.add(new Observer1());
        sub.add(new Observer2());
        sub.operation();
    }

    /**
     * 集合里的迭代器
     */
    public static void 迭代子模式() {
        Collection collection = new MyCollection();
        Iterator it = collection.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }

    /**
     * 任务交给一条链上的对象去执行，可以是一条链，也可以是一条环，或者一个树，同时，在同一时刻，命令只允许由一个对象传给另一个对象
     */
    public static void 责任链模式() {
        MyHandler h1 = new MyHandler("h1");
        MyHandler h2 = new MyHandler("h2");
        MyHandler h3 = new MyHandler("h3");
        h1.setHandler(h2);
        h2.setHandler(h3);
        h1.operator();
    }

    /**
     * 命令模式：请求与呈现的分离
     */
    public static void 命令模式() {
        Receiver receiver = new Receiver();     // 士兵
        Command cmd = new MyCommand(receiver);  // 命令
        Invoker invoker = new Invoker(cmd);     // 将军
        invoker.action();                       // 将军发命令
    }

    /**
     * 根据状态区分功能，如简单的权限控制等。
     */
    public static void 状态模式() {
        State state = new State();
        Context context = new Context(state);
        state.setValue("state1");
        context.method();
        state.setValue("state2");
        context.method();
    }

    /**
     * 拥有创建备份和从备份中恢复的能力
     */
    public static void 备忘录模式() {
        Original origi = new Original("egg");
        Storage storage = new Storage(origi.createMemento());
        System.out.println("初始化状态为：" + origi.getValue());
        origi.setValue("niu");
        System.out.println("修改后的状态为：" + origi.getValue());
        origi.restoreMemento(storage.getMemento());
        System.out.println("恢复后的状态为：" + origi.getValue());
    }

    /**
     * 分离数据对象和行为，可为一被访问者动态添加新的操作而无需做其他修改。
     */
    public static void 访问者模式() {
        Visitor visitor = new MyVisitor();
        top.albertiy.访问者模式.Subject sub = new top.albertiy.访问者模式.MySubject();
        sub.accept(visitor);
    }

    /**
     * 降低类与类之间的耦合，将类与类之间的关系和调度交给mediator，有点类似spring容器
     */
    public static void 中介者模式() {
        Mediator mediator = new MyMediator();
        mediator.createMediator();
        mediator.workAll();
    }

    /** 主要应用于OOP开发中的编译器开发。比如正则表达式的解释器。 */
    public static void 解释器模式() {
        int result =
                new top.albertiy.解释器模式.Minus().interpret(new top.albertiy.解释器模式.Context(
                        new top.albertiy.解释器模式.Plus().interpret(new top.albertiy.解释器模式.Context(9, 2)), 8));
        System.out.println(result);
    }

    public static void main(String[] args) {
        // write your code here
//        普通工厂模式Test();
//        多个工厂方法模式Test();
//        静态工厂方法模式();
//        抽象工厂模式();
//        单例模式();
//        类的适配器模式();
//        对象的适配器模式();
//        接口的适配器模式();
//        装饰模式();
//        代理模式();
//        外观模式();
//        桥接模式();
//        组合模式();
//        策略模式();
//        模板方法模式();
//        观察者模式();
//        迭代子模式();
//        责任链模式();
//        命令模式();
//        状态模式();
//        备忘录模式();
//        访问者模式();
//        中介者模式();
        解释器模式();
    }
}
